package com.tgpay.iot.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 上游API服务 - 负责调用真实的充电桩API
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UpstreamApiService {
    
    private final RestTemplate restTemplate;
    
    @Value("${upstream.api.base-url:https://api.example.com}")
    private String upstreamBaseUrl;
    
    @Value("${upstream.api.app-id:your-app-id}")
    private String appId;
    
    @Value("${upstream.api.app-secret:your-app-secret}")
    private String appSecret;
    
    /**
     * 获取设备列表
     */
    public Object getDevices() {
        String url = upstreamBaseUrl + "/tg/iot/api/devices";
        HttpHeaders headers = createSignedHeaders("GET", "/tg/iot/api/devices", null);
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        
        log.info("调用上游API - 获取设备列表: {}", url);
        ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.GET, entity, Object.class);
        log.info("上游API返回 - 获取设备列表: {}", response.getBody());
        return response.getBody();
    }
    
    /**
     * 获取设备详情
     */
    public Object getDeviceDetail(String imei) {
        String path = "/tg/iot/api/devices/" + imei;
        String url = upstreamBaseUrl + path;
        HttpHeaders headers = createSignedHeaders("GET", path, null);
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        
        log.info("调用上游API - 获取设备详情: {}", url);
        ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.GET, entity, Object.class);
        log.info("上游API返回 - 获取设备详情: {}", response.getBody());
        return response.getBody();
    }
    
    /**
     * 启动充电
     */
    public Object startCharging(String imei, String portId, Map<String, Object> requestBody) {
        String path = "/tg/iot/api/devices/" + imei + "/ports/" + portId + "/start";
        String url = upstreamBaseUrl + path;
        HttpHeaders headers = createSignedHeaders("POST", path, requestBody);
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
        
        log.info("调用上游API - 启动充电: {}, 请求参数: {}", url, requestBody);
        ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.POST, entity, Object.class);
        log.info("上游API返回 - 启动充电: {}", response.getBody());
        return response.getBody();
    }
    
    /**
     * 停止充电
     */
    public Object stopCharging(String imei, String portId, Map<String, Object> requestBody) {
        String path = "/tg/iot/api/devices/" + imei + "/ports/" + portId + "/stop";
        String url = upstreamBaseUrl + path;
        HttpHeaders headers = createSignedHeaders("POST", path, requestBody);
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
        
        log.info("调用上游API - 停止充电: {}, 请求参数: {}", url, requestBody);
        ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.POST, entity, Object.class);
        log.info("上游API返回 - 停止充电: {}", response.getBody());
        return response.getBody();
    }
    
    /**
     * 获取设备状态
     */
    public Object getDeviceStatus(String imei) {
        String path = "/tg/iot/api/devices/" + imei + "/status";
        String url = upstreamBaseUrl + path;
        
        HttpHeaders headers = createSignedHeaders("GET", path, null);
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        
        log.info("调用上游API - 获取设备状态: {}", url);
        ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.GET, entity, Object.class);
        log.info("上游API返回 - 获取设备状态: {}", response.getBody());
        return response.getBody();
    }
    
    /**
     * 获取充电状态
     */
    public Object getChargingStatus(String imei, String portId, String orderNo) {
        String path = "/tg/iot/api/devices/" + imei + "/ports/" + portId + "/status";
        UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(upstreamBaseUrl + path);
        if (orderNo != null) {
            builder.queryParam("orderNo", orderNo);
        }
        String url = builder.toUriString();
        
        HttpHeaders headers = createSignedHeaders("GET", path, null);
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        
        log.info("调用上游API - 获取充电状态: {}", url);
        ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.GET, entity, Object.class);
        log.info("上游API返回 - 获取充电状态: {}", response.getBody());
        return response.getBody();
    }
    
    /**
     * 创建带签名的请求头
     */
    private HttpHeaders createSignedHeaders(String method, String path, Object body) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        
        long timestamp = System.currentTimeMillis();
        String signature = generateSignature(method, path, body, timestamp);
        
        headers.set("X-App-Id", appId);
        headers.set("X-Timestamp", String.valueOf(timestamp));
        headers.set("X-Signature", signature);
        
        return headers;
    }
    
    /**
     * 生成API签名
     * 参考前端实现：包含method、uri、timestamp以及查询参数和请求体参数
     */
    private String generateSignature(String method, String path, Object body, long timestamp) {
        try {
            // 构建签名参数 - 包含method、uri、timestamp
            Map<String, String> params = new TreeMap<>();
            params.put("method", method);
            params.put("uri", path);
            params.put("timestamp", String.valueOf(timestamp));
            
            // 如果是POST请求且有请求体，需要将请求体参数加入签名
            if (body != null && body instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> bodyMap = (Map<String, Object>) body;
                for (Map.Entry<String, Object> entry : bodyMap.entrySet()) {
                    if (entry.getValue() != null) {
                        if (entry.getValue() instanceof String || entry.getValue() instanceof Number || entry.getValue() instanceof Boolean) {
                            params.put(entry.getKey(), String.valueOf(entry.getValue()));
                        } else {
                            // 对于复杂对象，转换为JSON字符串
                            params.put(entry.getKey(), entry.getValue().toString());
                        }
                    }
                }
            }
            
            // 按key排序并构建签名字符串
            StringBuilder signStr = new StringBuilder();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                if (signStr.length() > 0) {
                    signStr.append("&");
                }
                signStr.append(entry.getKey()).append("=").append(entry.getValue());
            }
            
            log.debug("签名字符串: {}", signStr.toString());
            
            // 使用HMAC-SHA256算法生成签名
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);
            byte[] digest = mac.doFinal(signStr.toString().getBytes(StandardCharsets.UTF_8));
            
            // 转换为小写十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            
            String signature = hexString.toString().toLowerCase();
            log.debug("生成的签名: {}", signature);
            
            return signature;
        } catch (Exception e) {
            log.error("生成签名失败", e);
            throw new RuntimeException("生成签名失败", e);
        }
    }
}